﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Xml;
using System.Diagnostics;

namespace FtpServerAdministrator
{
    public class FileZillaConfiguration : IFtpServerConfigruation
    {

        public FileZillaConfiguration(String fileName)
        {
            this.fileName = fileName;
        }


        private void doAddingUser(FtpUser user)
        {
            var nodeNewUser = this.document.CreateElement("User");
            var nodeUserName = this.document.CreateAttribute("Name");
            nodeUserName.Value = user.UserName;
            nodeNewUser.Attributes.Append(nodeUserName);
            nodeNewUser.InnerXml = @"
                <Option Name='Pass'>" + this.convertPassword(user.Password) + @"</Option>
                <Option Name='Group'></Option>
                <Option Name='Bypass server userlimit'>0</Option>
                <Option Name='User Limit'>0</Option>
                <Option Name='IP Limit'>0</Option>
                <Option Name='Enabled'>1</Option>
                <Option Name='Comments'></Option>
                <Option Name='ForceSsl'>0</Option>
                <IpFilter>
                    <Disallowed />
                    <Allowed />
                </IpFilter>
                <Permissions>
                    <Permission Dir='" + user.Directory + "'>"+ this.getPermissionXml(user.Permissions) + @"</Permission>
                </Permissions>
                <SpeedLimits DlType='0' DlLimit='10' ServerDlLimitBypass='0' UlType='0' UlLimit='10' ServerUlLimitBypass='0'>
                    <Download />
                    <Upload />
                </SpeedLimits>";

            this.document.GetElementsByTagName("Users")[0].AppendChild(nodeNewUser);

        }

        public String getPermissionXml(FtpPermissions permissions)
        {
            Int32 listFiles = ((permissions & FtpPermissions.ListFiles) == FtpPermissions.ListFiles) ? 1 : 0;
            Int32 readFile = ((permissions & FtpPermissions.ReadFile) == FtpPermissions.ReadFile) ? 1 : 0;
            Int32 writeFile = ((permissions & FtpPermissions.WriteFile) == FtpPermissions.WriteFile) ? 1 : 0;
            Int32 deleteFile = ((permissions & FtpPermissions.DeleteFile) == FtpPermissions.DeleteFile) ? 1 : 0;
            Int32 makeDir = ((permissions & FtpPermissions.MakeDirectory) == FtpPermissions.MakeDirectory) ? 1 : 0;
            Int32 deleteDir = ((permissions & FtpPermissions.DeleteDirectory) == FtpPermissions.DeleteDirectory) ? 1 : 0;


            return String.Format(@"<Option Name='FileRead'>{0}</Option>
                        <Option Name='FileWrite'>{1}</Option>
                        <Option Name='FileDelete'>{2}</Option>
                        <Option Name='FileAppend'>{3}</Option>
                        <Option Name='DirCreate'>{4}</Option>
                        <Option Name='DirDelete'>{5}</Option>
                        <Option Name='DirList'>{6}</Option>
                        <Option Name='DirSubdirs'>{7}</Option>
                        <Option Name='IsHome'>1</Option>
                        <Option Name='AutoCreate'>0</Option>",
                                                             readFile,
                                                             writeFile,
                                                             deleteFile,
                                                             writeFile,
                                                             makeDir,
                                                             deleteDir,
                                                             listFiles,
                                                             makeDir);

        }

        public void AddUser(FtpUser user)
        {
            Boolean isBatchMode = this.isBatchMode;
            if (!isBatchMode)
                this.StartConfiguration();
            this.doAddingUser(user);
            if (!isBatchMode)
                this.EndConfiguration();
        }


        private String convertPassword(String password)
        {
            StringBuilder result = new StringBuilder();
            MD5 md5 = MD5.Create();
            byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
            for (int i = 0; i < bytes.Length; i++)
                result.Append(bytes[i].ToString("x2"));
            return result.ToString();
        }

        private XmlDocument document = new XmlDocument();
        private String fileName;
        private Boolean isBatchMode = false;

        public void StartConfiguration()
        {
            StreamReader reader = new StreamReader(fileName);
            this.document = new XmlDocument();
            this.isBatchMode = true;
            try
            {
                this.document.LoadXml(reader.ReadToEnd());
            }
            catch (XmlException)
            {
                throw;
            }
            finally
            {
                reader.Close();
            }
        }

        public void EndConfiguration()
        {
            this.document.Save(this.fileName);
            var files = new FileInfo(this.fileName).Directory.GetFiles();
            var exe = (from file in files
                       where file.Name == "FileZilla server.exe"
                       select file).First();
            Process fileZilla = Process.Start(exe.FullName, "/reload-config");

            fileZilla.WaitForExit();
            this.isBatchMode = false;
        }


        public void RemoveUser(string userName)
        {

            //TODO: Implement remove user from a FileZilla Server
            throw new NotImplementedException();
        }

        public void ModifyUser(string userName, FtpUser newUser)
        {
            //TODO: Implement modify some user's configuration from a FileZilla Server
            throw new NotImplementedException();
        }

        public FtpUser FindUser(string userName)
        {
            //TODO: Implement find some user's configuration by userName from a FileZilla Server
            throw new NotImplementedException();
        }
    }

}
